package com.douqu.game.battle.controller;

import com.douqu.game.battle.controller.sprite.PlayerController;
import com.douqu.game.battle.controller.sprite.SpriteController;
import com.douqu.game.battle.entity.BattleSkill;
import com.douqu.game.battle.entity.ExtendEffect;
import com.douqu.game.battle.entity.WaitToBattlefieldCard;
import com.douqu.game.battle.entity.aobject.BattleAObject;
import com.douqu.game.battle.entity.tmp.PlayerBattleTmp;
import com.douqu.game.battle.entity.tmp.SpriteBattleTmp;
import com.douqu.game.battle.server.GameServer;
import com.douqu.game.battle.util.BattleUtils;
import com.douqu.game.battle.util.MsgUtils;
import com.douqu.game.core.astar.AStar;
import com.douqu.game.core.astar.AstarMap;
import com.douqu.game.core.config.FunctionConfig;
import com.douqu.game.core.config.StableDataConfig;
import com.douqu.game.core.config.card.CardConfig;
import com.douqu.game.core.config.challenge.LevelConfig;
import com.douqu.game.core.config.common.Position;
import com.douqu.game.core.e.*;
import com.douqu.game.core.entity.battle.*;
import com.douqu.game.core.entity.common.TwoTuple;
import com.douqu.game.core.entity.db.CardDB;
import com.douqu.game.core.factory.ConstantFactory;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.factory.FunctionFactory;
import com.douqu.game.core.factory.WordFactory;
import com.douqu.game.core.i.IMainServer;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.protobuf.SGCommonProto.Pos;
import com.douqu.game.core.protobuf.SGMainProto.E_MSG_ID;
import com.douqu.game.core.protobuf.SGWarProto;
import com.douqu.game.core.util.CoreUtils;
import com.douqu.game.core.util.LogUtils;
import com.google.protobuf.InvalidProtocolBufferException;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;


/**
* Created by bean on 2017/7/18.
*/
public class BattleController {


    /** 公共出卡CD时间 */
    public final static int PUT_CARD_CD_TIME = 2 * ConstantFactory.UPDATE_BATTLE_TIME;

    /**
     * 出卡的列表的最大数量(其它的卡放在等待区)
     */
    public final static int PUT_CARD_COUNT = 4;

    /**
     * ID生成(上场的兵)
     */
    public int createSoldierUniqueId = 0;

    /**
     * ID生成(卡)
     */
    public int createCardUniqueId = 1000;

    /**
     * 技能ID生成器
     */
    public int createSkillUniqueId = 100;

    /**
     * 伤害序号
     */
    protected int damageIndex;

    protected String id;

    /**
     * 寻路类
     */
    protected AStar astar;

    /**
     * 战斗类型
     */
    protected E_BattleDetailType battleDetailType;

    protected SGCommonProto.E_BATTLE_TYPE battleType;

    /**
     * 观战的人
     */
    protected List<PlayerController> spectators = new CopyOnWriteArrayList<>();
    /**
     * 一局最长的时间
     */
    protected int maxBattleTime;

    /**
     * 战斗创建时间
     */
    protected int createTime;

    /**
     * 战斗开始时间
     */
    protected int startTime;

    protected int endTime;

    /**
     * 战斗持续时间
     */
    protected int battleTime;

    /**
     * 当前战斗状态
     */
    protected int status;

    protected SpriteController source;

    protected SpriteController target;

    /**
     * 初始化参数
     */
    protected BattleInitParam initParam;

    /** 是否是副本第一关 */
    protected boolean isFirstLevel;

    /**
     * 用来通知主服务器的数据
     */
    protected BattleDetail battleDetail;

    /**
     * 场上的所有兵
     */
    protected List<BattleAObject> soldiers;

    protected Map<Integer, BattleAObject> soldierMap;

    /**
     * 世界大BUFF(暴风雪)
     */
    private List<ExtendEffect> extendEffects;


    /**
     * 等待要上战场的卡(因为客户端发消息发早了服务器没通过检测的出卡,CD没到或者能量不够的,到了时间再出)
     */
    private List<WaitToBattlefieldCard> waitCardList = new CopyOnWriteArrayList<>();

    /**
     * 队伍2的数据
     */
    protected String targetData;

    /**
     * 有些特殊战斗类型需要动态生成名字，这里保存
     */
    protected String targetName;


    public BattleController(String battleId, SpriteController source, SpriteController target, SGCommonProto.E_BATTLE_TYPE battleType, E_BattleDetailType battleDetailType, String targetData, String targetName, BattleInitParam initParam)
    {
        this.id = battleId;
        this.source = source;
        this.target = target;
        this.battleType = battleType;
        this.battleDetailType = battleDetailType;
        this.targetData = targetData;
        this.targetName = targetName;
        this.initParam = initParam;

        if(initParam instanceof BattleInitParamInstance)
        {
            int levelId = ((BattleInitParamInstance) initParam).getLevelId();
            List<LevelConfig> list = DataFactory.getInstance().getDataList(DataFactory.LEVEL_KEY);
            isFirstLevel = levelId == list.get(0).getId();
        }
        else
        {
            isFirstLevel = false;
        }

        source.setBattleController(this);
        source.setStatus(E_PlayerStatus.BATTLE_WAIT_START);
        target.setBattleController(this);
        target.setStatus(E_PlayerStatus.BATTLE_WAIT_START);

        soldiers = new CopyOnWriteArrayList<>();
        soldierMap = new ConcurrentHashMap<>();
        extendEffects = new CopyOnWriteArrayList<>();

        battleDetail = new BattleDetail(GameServer.getInstance().getId(), initParam);
    }

    public void init()
    {
        StableDataConfig stableDataConfig = DataFactory.getInstance().getGameObject(DataFactory.STABLE_DATA_KEY, E_StableDataType.CRYSTAL_GROW.getCode());
        if (stableDataConfig == null){
            LogUtils.error("StableDataConfig error ->" + "no have type " + E_StableDataType.CRYSTAL_GROW.getMsg());
            return;
        }

        this.maxBattleTime = stableDataConfig.commons[stableDataConfig.commons.length-1].id;

        this.createTime = (int) (DataFactory.currentTime/1000);

        SpriteBattleTmp pbt1 = new PlayerBattleTmp();
        pbt1.init(this, source, ConstantFactory.BATTLE_TEAM_1);
        source.setAttachment(pbt1);

        battleDetail.setId(id);
        battleDetail.setCreateTime(createTime);
        battleDetail.setBattleType(battleType.getNumber());
        battleDetail.setBattleDetailType(battleDetailType.getCode());
        battleDetail.getTeam1Info().setIndexInfo(source.getObjectIndex());
        battleDetail.getTeam2Info().setIndexInfo(target.getObjectIndex());
        battleDetail.getTeam1Info().setMaster(pbt1.getMasterSoldier().getSpriteTemp());
    }

    public void updateCrystal()
    {
        if(startTime <= 0)
        {
//            LogUtils.info("还没开始战斗呢!" + id);
            return;
        }

        if(endTime > 0)
        {
            return;
        }

        battleTime += ConstantFactory.UPDATE_BATTLE_TIME;

        if(battleTime < maxBattleTime)
        {
            source.getAttachment().updateCrystal(battleTime);
            if(checkEnd())
                return;

            target.getAttachment().updateCrystal(battleTime);
            if(checkEnd())
                return;
        }
    }

    /**
     *
     * @param currentTime 当前时间
     */
    public void update(long currentTime)
    {
        if(startTime <= 0)
        {
//            LogUtils.info("还没开始战斗呢!" + id);
            return;
        }

        if(endTime > 0)
        {
            LogUtils.warn("战斗已经结束了->" + this);
            return;
        }

        if(battleTime >= maxBattleTime)//战斗时间到了
        {
            //战斗时间到了,检测胜负
            TwoTuple<E_BattleEnd, Integer> winTeam = getWinTeam();
            if(winTeam.getSecond() == -1)
                return;

            if(winTeam.getSecond() == 0)
            {
                if(source.getAttachment().getMasterSoldier().getHp() >= target.getAttachment().getMasterSoldier().getHp())
                    end(source.getAttachment().getTeamNo(), E_BattleEnd.TIME_END);
                else
                    end(target.getAttachment().getTeamNo(), E_BattleEnd.TIME_END);
            }
            else
                end(winTeam.getSecond(), E_BattleEnd.TIME_END);
        }
        else//时间没到
        {
            if(checkEnd())
            {
                LogUtils.debug("战斗已经结束 -> " + this);
                return;
            }

            for(WaitToBattlefieldCard waitCard : waitCardList)
            {
                if(waitCard.checkToBattlefield())
                {
                    waitCardList.remove(waitCard);
                }
            }

            for(ExtendEffect extendEffect : extendEffects)
            {
                extendEffect.update(currentTime);

                if(extendEffect.isEnd())
                    extendEffects.remove(extendEffect);
            }

            if(checkEnd())
            {
                LogUtils.debug("战斗已经结束 -> " + this);
                return;
            }

            source.getAttachment().update(currentTime);

            if(checkEnd())
            {
                LogUtils.debug("战斗已经结束 -> " + this);
                return;
            }
            target.getAttachment().update(currentTime);

            if(checkEnd())
            {
                LogUtils.debug("战斗已经结束 -> " + this);
                return;
            }
        }
    }

    public boolean isStarted()
    {
        return startTime > 0;
    }

    /**
     * 是否过期
     * @return
     */
    public boolean isOverdue()
    {
        return startTime == 0 && DataFactory.currentTime/1000 - createTime >= ConstantFactory.BATTLE_OVERDUE_TIME;
    }

    public void setToAstarMap(BattleAObject battleAObject)
    {
        if(battleAObject.getObjectBound().center == null)
            return;

        try {
            astar.getAstarMap().setMap(battleAObject.getObjectBound(), AstarMap.MapSignal.Player);
        }catch (Exception e){
            e.printStackTrace();
            LogUtils.error(e.getMessage() + " 设置位置出错 setToAstarMap -> " + battleAObject);
        }
    }

    public void leaveAstarMap(BattleAObject battleAObject)
    {
        if(battleAObject.getObjectBound().center == null)
            return;

        try {
            astar.getAstarMap().setMap(battleAObject.getObjectBound(), AstarMap.MapSignal.Free);
        }catch (Exception e){
            LogUtils.error(e.getMessage() + " 设置位置出错leaveAstarMap -> " + battleAObject);
        }
    }


    public void addSoldier(BattleAObject battleAObject)
    {
        soldiers.add(battleAObject);
        soldierMap.put(battleAObject.getUniqueId(), battleAObject);

//        if(battleAObject.getTeamNo() == ConstantFactory.BATTLE_TEAM_1)
//        {
//            battleDetail.getTeam1Info().addSoldierTemp(battleAObject.getSpriteTemp());
//        }
//        else
//        {
//            battleDetail.getTeam2Info().addSoldierTemp(battleAObject.getSpriteTemp());
//        }
    }

    public void removeSoldier(BattleAObject soldier)
    {
        soldiers.remove(soldier);
        soldierMap.remove(soldier.getUniqueId());

        if(soldier.getTeamNo() == ConstantFactory.BATTLE_TEAM_1)
        {
            source.getAttachment().removeSoldier(soldier);
        }
        else
        {
            target.getAttachment().removeSoldier(soldier);
        }

        leaveAstarMap(soldier);
    }

    public List<BattleAObject> getSoldiers()
    {
        return soldiers;
    }

    public BattleAObject getSoldier(int uniqueId)
    {
        return soldierMap.get(uniqueId);
    }

    public BattleAObject getBattleAObject(int teamNo, int uniqueId)
    {
        if(source.getAttachment() == null)
            return null;

        if(teamNo == source.getAttachment().getTeamNo())
        {
            if(source.getAttachment().getMasterSoldier().getUniqueId() == uniqueId)
                return source.getAttachment().getMasterSoldier();
        }
        else
        {
            if(target.getAttachment().getMasterSoldier().getUniqueId() == uniqueId)
                return target.getAttachment().getMasterSoldier();
        }

        return getSoldier(uniqueId);
    }


    public void addExtendEffect(BattleAObject releaser, BattleSkill skill, Position sourcePoint, Position directionPoint)
    {
        ExtendEffect extendEffect = new ExtendEffect(releaser, skill, sourcePoint, directionPoint);
        extendEffects.add(extendEffect);
    }



    private boolean checkEnd()
    {
        TwoTuple<E_BattleEnd, Integer> winTeam = getWinTeam();
        if(winTeam.getSecond() > 0)
        {
            end(winTeam.getSecond(), winTeam.getFirst());
            return true;
        }

        return false;
    }


    public void readyStart()
    {
        source.setStatus(E_PlayerStatus.BATTLE_ING);
        target.setStatus(E_PlayerStatus.BATTLE_ING);

        final long currentTime = DataFactory.currentTime;
        startTime = (int) (currentTime/1000);
        source.getAttachment().getMasterSoldier().initSkillReleaseTime(currentTime);
        target.getAttachment().getMasterSoldier().initSkillReleaseTime(currentTime);
        battleDetail.setStartTime(startTime);
        battleTime = 0;
    }

    public void ready(PlayerController playerController)
    {
        if(playerController.getStatus() != E_PlayerStatus.BATTLE_WAIT_START)
            return;

        SpriteBattleTmp spriteBattleTmp = playerController.getAttachment();
        if(spriteBattleTmp == null)
            return;

        spriteBattleTmp.setReady(true);

        if(isReady())
        {
            readyStart();

            IMainServer server = GameServer.getInstance().getIMainServer();
            if(server != null)
            {
                try {
                    server.battleStart(battleDetail);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            dispatchMsg(E_MSG_ID.MsgID_War_ReadyStart_VALUE, null);
        }
    }


    public void end(int winTeam, E_BattleEnd endType)
    {
        if(winTeam < 0 || endTime > 0)
            return;

        LogUtils.warn("战斗结束 -> 胜利方: " + winTeam + ",VS:" + toString() + ",endType:" + endType + ",id:" + id);

        endTime = (int) (DataFactory.currentTime/1000);

        battleDetail.setEndTime(endTime);
        battleDetail.setWinTeam(winTeam);
        battleDetail.setEndType(endType.name());

        int star1 = getStar(source.getAttachment(), winTeam);
        if(star1 <= 0)
        {
            if(winTeam == source.getAttachment().getTeamNo())
                star1 = Integer.valueOf("100", 2);
        }

        battleDetail.getTeam1Info().setStar(star1);

        initBattleTempData(battleDetail.getTeam1Info(), source.getAttachment());
        initBattleTempData(battleDetail.getTeam2Info(), target.getAttachment());

        BattleResultParam resultParam = null;
        try{
//            LogUtils.warn("通知主服战斗结果 -> " + resultParam);
            resultParam = GameServer.getInstance().getIMainServer().battleEnd(battleDetail);
//            LogUtils.warn("通知主服战斗结果成功，获取到数据 -> " + resultParam);
        }catch (Exception e){
            e.printStackTrace();
            LogUtils.errorException(e);
        }

        MsgUtils.sendBattleResult(source, target, battleType, winTeam, resultParam, star1);
        MsgUtils.sendBattleResult(target, source, battleType, winTeam, resultParam, 0);

        //通知双方战斗结束，计算战斗奖励
        source.clearBattle();
        target.clearBattle();

        GameServer.getInstance().getWorldManager().removeBattleController(this);
    }


    private void initBattleTempData(BattleTemp battleTemp, SpriteBattleTmp spriteBattleTmp)
    {
        battleTemp.setMaster(spriteBattleTmp.getMasterSoldier().getSpriteTemp());

        SpriteTemp soldierTemp = null;
        boolean merge =  battleType != SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_WORLD_BOSS && spriteBattleTmp instanceof PlayerBattleTmp;
        for(BattleAObject soldier : spriteBattleTmp.getHistorySoldiers())
        {
            if(soldier.isInitObject() && soldier.getSpriteTemp() != null)
                battleTemp.addSoldierTemp(soldier.getSpriteTemp(), merge);
        }
        for(CardDB cardDB : spriteBattleTmp.getCardList())
        {
            soldierTemp = spriteBattleTmp.getSoldierHistoryTemp(cardDB.id, cardDB.getIndex());
            if(soldierTemp != null)
            {
                battleTemp.addSoldierTemp(soldierTemp, merge);
            }
            else
            {
                int hp = cardDB.getAttribute(E_Attribute.HP.getCode());
                battleTemp.addSoldierTemp(new SpriteTemp(cardDB.id, cardDB.getLv(), hp, hp, hp, cardDB.getIndex()), merge);
            }
        }
        for(SpriteTemp spriteSoldierTemp : spriteBattleTmp.getHistoryDeadSoldiers())
        {
            battleTemp.addSoldierTemp(spriteSoldierTemp, merge);
        }

        LogUtils.debug("---------战斗结束 -> " + battleTemp.getSoldierList());
    }

    public int getStar(SpriteBattleTmp spriteBattleTmp, int winTeam)
    {
        return 0;
    }


    public TwoTuple<E_BattleEnd, Integer> getWinTeam()
    {
        if(endTime > 0 || source == null || source.getAttachment() == null || target == null || target.getAttachment() == null)
            return new TwoTuple<>(E_BattleEnd.END_ERROR, -1);

        if(!source.getAttachment().isHaveSoldier() && battleType != SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_WORLD_MAP)
        {
            LogUtils.debug("自己没有兵了,判定输!");
            return new TwoTuple<>(E_BattleEnd.SOLDIER_ZERO, target.getAttachment().getTeamNo());
        }

        if(!isHaveSoldier())
        {
            LogUtils.debug("场上没有兵了,判定挑战方输!");
            return new TwoTuple<>(E_BattleEnd.SOLDIER_ZERO, target.getAttachment().getTeamNo());
        }

        if(source.getAttachment().isDie())
            return new TwoTuple<>(E_BattleEnd.DEFAULT, target.getAttachment().getTeamNo());

        if(target.getAttachment().isDie())
            return new TwoTuple<>(E_BattleEnd.DEFAULT, source.getAttachment().getTeamNo());

        return new TwoTuple<>(E_BattleEnd.NOT_END, 0);
    }



    private boolean isHaveSoldier()
    {
        return soldiers.size() > 0 || source.getAttachment().getCardList().size() > 0 || target.getAttachment().getCardList().size() > 0;
    }


    public boolean isEnd()
    {
        return getWinTeam().getSecond() > 0;
    }


    /**
     * 是否需要记录生命值
     * @return
     */
    public boolean isRecordHP()
    {
        return battleType == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_SPAN_CAMP || battleType == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_WORLD_BOSS || battleType == SGCommonProto.E_BATTLE_TYPE.BATTLE_TYPE_WORLD_MAP;
    }



    public boolean isReady()
    {
        if(battleDetailType.isBothPlayer())
            return source.getAttachment().isReady() && target.getAttachment().isReady();
        else
            return source.getAttachment().isReady();
    }


    public Position getMasterPos(int teamNo, int gridArea)
    {
        if(teamNo == ConstantFactory.BATTLE_TEAM_1)
        {
            return new Position(gridArea, astar.getAstarMap().height>>1);
        }
        else
        {
            return new Position(astar.getAstarMap().width-gridArea-1, astar.getAstarMap().height>>1);
        }
    }




    public void destroy()
    {
        if(source instanceof PlayerController)
        {
            GameServer.getInstance().getWorldManager().playerExitGame((PlayerController) source);
        }

        if(target instanceof PlayerController)
        {
            GameServer.getInstance().getWorldManager().playerExitGame(((PlayerController) target));
        }
    }




    /**
     * 获取目标组
     * @param targetGroup
     * @param spriteBattleTmp
     * @return
     */
    public List<BattleAObject> getTargetsByGroup(int targetGroup, SpriteBattleTmp spriteBattleTmp)
    {
        List<BattleAObject> result = new CopyOnWriteArrayList<>();
        if(targetGroup == ConstantFactory.EFFECT_TARGET_GROUP_ALL)
        {
            result.addAll(soldiers);
            result.add(spriteBattleTmp.getMasterSoldier());
            result.add(spriteBattleTmp.getTargetBattleTmp().getMasterSoldier());
        }
        else if(targetGroup == ConstantFactory.EFFECT_TARGET_GROUP_PARTNER)
        {
            result.addAll(spriteBattleTmp.getSoldierList());
            result.add(spriteBattleTmp.getMasterSoldier());
        }
        else if(targetGroup == ConstantFactory.EFFECT_TARGET_GROUP_ENEMY)
        {
            result.addAll(spriteBattleTmp.getTargetBattleTmp().getSoldierList());
            result.add(spriteBattleTmp.getTargetBattleTmp().getMasterSoldier());
        }
        else if(targetGroup == ConstantFactory.EFFECT_TARGET_GROUP_SELF)
        {
            result.addAll(result);
        }

        return result;
    }



    public String getId() {
        return id;
    }

    public E_BattleDetailType getBattleDetailType() {
        return battleDetailType;
    }

    public SGCommonProto.E_BATTLE_TYPE getBattleType() {
        return battleType;
    }

    public int getBattleTime() {
        return battleTime;
    }

    public PlayerController getPlayerByIndex(String playerIndex)
    {
        if(source instanceof PlayerController && playerIndex.equals(source.getObjectIndex()))
            return (PlayerController) source;

        if(target instanceof PlayerController && playerIndex.equals(target.getObjectIndex()))
            return (PlayerController) target;

        return null;
    }

    public SpriteController getSource() {
        return source;
    }

    public SpriteController getTarget() {
        return target;
    }

    public AStar getAstar()
    {
        return astar;
    }

    public String getTargetData() {
        return targetData;
    }

    public BattleInitParam getInitParam() {
        return initParam;
    }

    /**
     * 更新要通知主服务器的数据
     */
    public BattleDetail getBattleDetail()
    {
        return battleDetail;
    }

    public int getSoldierUniqueId()
    {
        return ++createSoldierUniqueId;
    }

    public String getSkillUniqueId(int skillId, int releaserId)
    {
        return skillId + "_" + releaserId + "_" + (++createSkillUniqueId);
    }

    public synchronized int getDamageIndex()
    {
        return ++damageIndex;
    }

    /**
     * 是否是第一关
     * @return
     */
    public boolean isFirstLevel()
    {
        return isFirstLevel;
    }

    public int getCardUniqueId()
    {
        return ++createCardUniqueId;
    }


    /**
     * 转发容器内所有的消息
     * @param
     */
    public void dispatchMsg(int code, byte[] data)
    {
        source.sendMsg(code, data);

        target.sendMsg(code, data);

        for(PlayerController playerController : spectators)
        {
            playerController.sendMsg(code ,data);
        }
    }


    //---------------------------------------------消息通道-----------------------------------------------------------------------
    /**
     * 上战场
     * @param playerController
     * @param data
     */
    public void toBattlefield(PlayerController playerController, byte[] data) throws InvalidProtocolBufferException
    {
        if(isEnd())
        {
            LogUtils.error("战斗已经结束");
            playerController.sendWarn(WordFactory.ILLEGAL_ERROR);
            return;
        }

        PlayerBattleTmp playerBattleTmp = (PlayerBattleTmp) playerController.getAttachment();
        if(playerBattleTmp == null)
        {
            //错误
            LogUtils.error("非法数据");
            playerController.sendWarn(WordFactory.ILLEGAL_ERROR);
            return;
        }
        if(playerBattleTmp.isAuto())
        {
            LogUtils.error("自动战斗时不允许手动出卡");
            return;
        }
//        if(DataFactory.currentTime < playerBattleTmp.getNextPutCardTime())
//        {
//            LogUtils.warn("出卡太快 -> " + DataFactory.currentTime + " " + playerBattleTmp.getNextPutCardTime());
//            playerController.sendWarn(WordFactory.CD_TIME_ERROR);
//            return;
//        }
        SGWarProto.C2S_ToBattle request = SGWarProto.C2S_ToBattle.parseFrom(data);
        CardDB cardDB = playerBattleTmp.getCardById(request.getCardId());
        if(cardDB == null)
        {
            //没有此卡牌
            LogUtils.error("卡牌不存在");
            playerController.sendWarn(WordFactory.OBJECT_NOT_EXIST);
            return;
        }
        List<Pos> posList = request.getPosList();
//        List<Pos> posList = new ArrayList<>();
//        Pos.Builder poss = Pos.newBuilder();
//        poss.setX(2);
//        poss.setY(2);
//        posList.add(poss.build());

        CardConfig cardConfig = cardDB.getConfig();
        if(posList.isEmpty())
        {
            //参数错误
            LogUtils.error("位置数量不对 -> " + posList);
            playerController.sendWarn(WordFactory.ILLEGAL_ERROR);
            return;
        }

        //位置范围检测
        List<Position> positionList = new ArrayList<>();
        Position p = null;
        for(Pos pos : posList)
        {
            p = new Position(pos);
            if(ConstantFactory.BATTLE_TEAM_1 == playerBattleTmp.getTeamNo())
            {
                if(pos.getX() > cardConfig.getSoldier().initRange)
                {
                    LogUtils.error("释放位置超出限制 : " + pos.getX() + " initRange:" + cardConfig.getSoldier().initRange);
                    playerController.sendWarn(WordFactory.PARAM_ERROR);
                    return;
                }
            }
            else if(ConstantFactory.BATTLE_TEAM_2 == playerBattleTmp.getTeamNo())
            {
                if(pos.getX() < astar.getAstarMap().width - cardConfig.getSoldier().initRange)
                {
                    LogUtils.error("释放位置超出限制 : " + pos.getX() + " initRange:" + cardConfig.getSoldier().initRange);
                    playerController.sendWarn(WordFactory.PARAM_ERROR);
                    return;
                }
            }

            BattleUtils.fixSoldierPositionBorder(astar.getAstarMap(), p);
            positionList.add(p);
        }

        Position first = positionList.get(0);
        int posCount = posList.size();
        if(posCount < cardConfig.soldierCount)
        {
            positionList.addAll(BattleUtils.getSoldierSummonPos(astar.getAstarMap(), playerBattleTmp.getTeamNo(), cardConfig.soldierCount-posCount, first, cardConfig.getSoldier().gridArea, cardConfig.getSoldier().gridArea));
        }

        LogUtils.debug("释放士兵 -> " + cardConfig);
        LogUtils.debug("释放位置 -> " + positionList);

        if(playerBattleTmp.getCurCrystal() < cardConfig.crystal || DataFactory.currentTime < playerBattleTmp.getNextPutCardTime()) {
            LogUtils.warn("服务器检测不满足出卡条件,放入等待列表中------->" + cardConfig.getId() + "," + cardConfig.getName());
            waitCardList.add(new WaitToBattlefieldCard(playerBattleTmp, cardDB, positionList));
        }
        else
        {
            playerBattleTmp.soldierBorn(cardDB, positionList);

            if(!battleDetailType.isBothPlayer())
            {
                //检测AI
//            LogUtils.debug("对手开始检测AI出牌：" + target);
                target.getAttachment().checkAI(DataFactory.currentTime);
            }
        }

    }





    /**
     * 同步位置
     * @param playerController
     * @param data
     */
    private void synPos(PlayerController playerController, byte[] data) throws InvalidProtocolBufferException
    {
        SGWarProto.C2S_SynPos request = SGWarProto.C2S_SynPos.parseFrom(data);

//        request.get
    }



    /**
     * 主将使用技能
     * @param playerController
     * @param data
     */
    public void useSkill(PlayerController playerController, byte[] data) throws InvalidProtocolBufferException
    {
        SGWarProto.C2S_UseSkill request = SGWarProto.C2S_UseSkill.parseFrom(data);

        PlayerBattleTmp playerBattleTmp = (PlayerBattleTmp) playerController.getAttachment();
        if(playerBattleTmp == null)
            return;

        if(playerBattleTmp.isAuto())
        {
            LogUtils.warn("自动战斗时不允许手动操作");
            playerController.sendWarn(WordFactory.ILLEGAL_ERROR);
            return;
        }

        if(playerBattleTmp.isDie())
        {
            LogUtils.error("已经死亡了，不能再操作 -> " + playerController.getName());
            playerController.sendWarn(WordFactory.ILLEGAL_ERROR);
            return;
        }
//        if(DataFactory.currentTime < playerBattleTmp.getNextUserSkillTime())
//        {
//            //公共CD时间没到
//            playerController.sendWarn(WordFactory.CD_TIME_ERROR);
//            return;
//        }

        BattleSkill skill = playerBattleTmp.getMasterSoldier().getSkill(request.getSkillId());
        if(skill == null)
        {
            //没有这个技能
            LogUtils.error("技能不存在 -> " + request.getSkillId() + "  " + playerController.getName());
            playerController.sendWarn(WordFactory.SKILL_NOT_EXIST);
            return;
        }

        if(playerBattleTmp.getCurCrystal() < skill.getSkillConfig().crystal)
        {
            //水晶不够
            LogUtils.error("水晶不够 -> " + playerController.getName());
            playerController.sendWarn(WordFactory.ENERGY_NOT_ENOUGH);
            return;
        }

        if(skill.getSkillConfig().type != ConstantFactory.SKILL_TYPE_MASTER)
        {
            //非主将技能不能手动释放
            LogUtils.error("不是主将技能，不能手动施放 -> " + playerController.getName());
            playerController.sendWarn(WordFactory.ILLEGAL_ERROR);
            return;
        }

        if(!skill.isCanRelease())
        {
            //cd时间没到
            playerController.sendWarn(WordFactory.CD_TIME_ERROR);
            return;
        }

        Pos pos = request.getPos();
        if(skill.getSkillConfig().effectTargetType == ConstantFactory.EFFECT_TARGET_TYPE_POINT && pos == null)
        {
            //参数错误
            playerController.sendWarn(WordFactory.PARAM_ERROR);
            return;
        }

        LogUtils.debug("施放主将技能 -> " + skill.getSkillConfig().getName() + "  " + request.getPos());

        if(skill.getSkillConfig().effectTargetType == ConstantFactory.EFFECT_TARGET_TYPE_POINT)
        {
            Position position = new Position(pos);
            position.x = astar.getAstarMap().fixBorderX(position.x);
            position.y = astar.getAstarMap().fixBorderY(position.y);
            skill.releaseByPoint(position);
        }
        else
            skill.release();

//        playerBattleTmp.setNextUserSkillTime(DataFactory.currentTime + USER_SKILL_CD_TIME);
        playerBattleTmp.addCrystal(-skill.getSkillConfig().crystal);

    }

    private void autoBattle(PlayerController playerController, byte[] data) throws InvalidProtocolBufferException
    {
        SGWarProto.C2S_AutoBattle request = SGWarProto.C2S_AutoBattle.parseFrom(data);
        LogUtils.debug("自动战斗收包 -> " + request.getBegin());
        if(request.getBegin())
        {
            StableDataConfig stableData = DataFactory.getInstance().getGameObject(DataFactory.STABLE_DATA_KEY, E_StableDataType.AUTO_BATTLE_VIP_LV.getCode());
            if(stableData != null && playerController.getPlayer().getVipLevel() < stableData.intValue)
            {
                String errorMessage = CoreUtils.checkFunctionOpen(FunctionFactory.UNLOCK_AUTO_BATTLE,playerController.getPlayer());
                if (errorMessage != null){
                    LogUtils.error(errorMessage);
                    FunctionConfig functionConfig = DataFactory.getInstance().getGameObject(DataFactory.FUNCTION_KEY, FunctionFactory.UNLOCK_AUTO_BATTLE);
                    playerController.sendWarn(WordFactory.AUTO_BATTLE_VIP_LV, stableData.intValue, functionConfig.lv);
                    playerController.sendMsg(E_MSG_ID.MsgID_War_AutoBattle_VALUE, SGWarProto.S2C_AutoBattle.newBuilder().setBegin(false).build().toByteArray());
                    return;
                }
            }
        }

        playerController.getAttachment().setAuto(request.getBegin());
        playerController.sendMsg(E_MSG_ID.MsgID_War_AutoBattle_VALUE, SGWarProto.S2C_AutoBattle.newBuilder().setBegin(request.getBegin()).build().toByteArray());

        LogUtils.debug("设置自动战斗 -> " + request.getBegin());

        GameServer.getInstance().pingToMain(id);
    }


    /** 消息通道
     */
    public void messageChannel(int code, PlayerController playerController, byte[] data)
    {
        SpriteBattleTmp battleTmp = playerController.getAttachment();
        if(battleTmp == null)
            return;

        if(battleTmp.getTeamNo() == ConstantFactory.BATTLE_TEAM_SPECTATOR)
        {
            //观战者
            LogUtils.error("观战----" + playerController.getName());
            playerController.sendUnknown();
            return;
        }

        if(code == E_MSG_ID.MsgID_War_AutoBattle_VALUE)
        {//自动战斗
            try {
                autoBattle(playerController, data);
            } catch (InvalidProtocolBufferException e) {
                e.printStackTrace();
                playerController.sendWarn(WordFactory.PARAM_ERROR);
            }
            return;
        }

//        LogUtils.info(playerController.getName() + "  当前玩家状态："+playerController.getStatus() + "  " + playerController.getBattleController());

        if(code == E_MSG_ID.MsgID_War_ReadyStart_VALUE)
        {
            if(playerController.getStatus() != E_PlayerStatus.BATTLE_WAIT_START)
            {
                LogUtils.debug("非法请求一直在发ReadyStart -> " + playerController);
                playerController.sendUnknown();
                return;
            }
            ready(playerController);
            return;
        }
        if(playerController.getStatus() != E_PlayerStatus.BATTLE_ING || playerController.getAttachment() == null)
        {
            LogUtils.debug("Error----------> code:" + code + " source:" + playerController.getName());
            playerController.sendUnknown();
            return;
        }
        if(!isCanOption(code))
        {
            LogUtils.error("不能操作..........code:" + code + " source:" + playerController.getName() + " battleDetailType:" + battleDetailType);
            playerController.sendUnknown();
            return;
        }

        try{
            switch (code)
            {
                case E_MSG_ID.MsgID_War_ToBattle_VALUE://出牌
                    toBattlefield(playerController, data);
                    break;
                case E_MSG_ID.MsgID_War_SynPos_VALUE://同步位置
                    synPos(playerController, data);
                    break;
                case E_MSG_ID.MsgID_War_UseSkill_VALUE://使用技能
                    useSkill(playerController, data);
                    break;
                case E_MSG_ID.MsgID_War_Surrender_VALUE://投降
                    LogUtils.debug("投降------>" + playerController.getName());
                    end(playerController.getObjectIndex().equals(source.getObjectIndex()) ? target.getAttachment().getTeamNo() : source.getAttachment().getTeamNo(), E_BattleEnd.SURRENDER);
                    break;
//                case E_MSG_ID.MsgID_War_Pause_VALUE://暂停
//                    pauseBattle(playerController, data);
//                    break;
            }
        }catch (Exception e){
            LogUtils.info("Error: code:" + code +" " + e.getLocalizedMessage());
            e.printStackTrace();
            playerController.sendWarn(WordFactory.PARAM_ERROR);
        }

    }

    public boolean isCanOption(int code)
    {
        switch (code)
        {
            case E_MSG_ID.MsgID_War_ToBattle_VALUE://出牌
            case E_MSG_ID.MsgID_War_SynPos_VALUE://同步位置
            case E_MSG_ID.MsgID_War_UseSkill_VALUE://使用技能
            case E_MSG_ID.MsgID_War_AutoBattle_VALUE://自动战斗
                return battleDetailType != E_BattleDetailType.PVP_AI_ARENA;
        }

        return true;
    }




    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof BattleController)) return false;

        BattleController that = (BattleController) o;

        if (!id.equals(that.id)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }


    @Override
    public String toString() {
        return "[" + source.getObjectIndex() + "-" + source.getName() + " ---VS--- " + target.getObjectIndex() + "-" + target.getName() + "] type:" + battleDetailType;
    }
}
